/*
 * Copyright 2024 The CHANGLEI Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:fibber/src/logger.dart';
import 'package:fibber/src/name.dart';
import 'package:path/path.dart' as path;

const _npmPluginName = r'fantasticon';

final _buildDirectory = Directory.fromUri(Platform.script.resolve(r'..'));
final _tempDirectory = Directory(path.join(_buildDirectory.path, r'temp'));
final _nodeDirectory = Directory(path.join(_tempDirectory.path, r'node'));
final _outputDirectory = Directory(path.join(_tempDirectory.path, r'out'));
final _nodeExecutablePath = path.join(_nodeDirectory.path, r'node_modules', r'.bin', _npmPluginName);

Future<Map<String, dynamic>?> generateTTF(String input, String ttfOutput, String classname) async {
  try {
    await _judgeNodeEnvironment();
    await _generatePackageJson();
    await _generateTTF(input, classname);

    final jsonFontsFile = File(path.join(_outputDirectory.path, '${classname.headerCased}.json'));
    return Map.unmodifiable(json.decode(jsonFontsFile.readAsStringSync()) as Map<dynamic, dynamic>);
  } catch (e) {
    Level.error.writeln(
      switch (e) {
        ProcessException(:final message) => '生成字体图标失败：$message',
        _ => '生成字体图标失败：$e',
      },
    );
    return null;
  } finally {
    _copyFileAndDeleteTemp(ttfOutput, classname);
  }
}

Future<void> _judgeNodeEnvironment() async {
  final process = await Process.start(
    r'node',
    <String>[r'--version'],
    runInShell: true,
  );

  final exitCode = await process.exitCode;
  if (exitCode != 0) {
    Level.error.writeln(r'请安装NodeJS。建议安装V10+，您可以点击"https://nodejs.org/en"进行安装！');
  }
}

Future<void> _generatePackageJson() async {
  if (!_nodeDirectory.existsSync()) {
    _nodeDirectory.createSync(recursive: true);
  }

  Level.verbose.write(r'正在安装`npm`依赖项...');

  final arguments = <String>[
    r'install',
    r'fantasticon',
    r'--registry=https://mirrors.huaweicloud.com/repository/npm/',
  ];
  final process = await Process.start(
    r'npm',
    arguments,
    workingDirectory: _nodeDirectory.path,
    runInShell: true,
  );

  final timer = Timer.periodic(const Duration(milliseconds: 100), (timer) {
    final time = (timer.tick / 10).toStringAsFixed(1);
    Level.verbose.rewrite('正在安装`npm`依赖项... ${Level.info('(${time}s)')}');
  });

  final exitCode = await process.exitCode.whenComplete(() {
    timer.cancel();
    Level.normal.writeln();
  });

  if (exitCode != 0) {
    final messages = [
      ...await process.stdout.transform(utf8.decoder).toList(),
      ...await process.stderr.transform(utf8.decoder).toList(),
    ];
    final message = messages.join();

    throw ProcessException(
      _nodeExecutablePath,
      arguments,
      message,
      exitCode,
    );
  }
}

Future<void> _generateTTF(String input, String classname) async {
  if (_outputDirectory.existsSync()) {
    _outputDirectory.deleteSync(recursive: true);
  }
  _outputDirectory.createSync(recursive: true);

  final arguments = <String>[
    path.join(path.current, input),
    r'--name',
    classname.headerCased,
    r'--output',
    _outputDirectory.path,
    r'--asset-types',
    r'json',
    r'--font-types',
    r'ttf',
    r'--normalize',
    r'true',
  ];
  final process = await Process.start(
    _nodeExecutablePath,
    arguments,
    runInShell: true,
  );

  final exitCode = await process.exitCode;
  if (exitCode != 0) {
    final messages = [
      ...await process.stdout.transform(utf8.decoder).toList(),
      ...await process.stderr.transform(utf8.decoder).toList(),
    ];
    final message = messages.join();

    throw ProcessException(
      _nodeExecutablePath,
      arguments,
      message,
      exitCode,
    );
  }
}

void _copyFileAndDeleteTemp(String ttfOutput, String classname) {
  final directory = Directory(ttfOutput);
  if (!directory.existsSync()) {
    directory.createSync(recursive: true);
  }
  final outputFile = File(path.join(directory.path, '${classname.headerCased}.ttf'));
  final iconFontsFile = File(path.join(_outputDirectory.path, '${classname.headerCased}.ttf'));
  if (iconFontsFile.existsSync()) {
    if (outputFile.existsSync()) {
      outputFile.deleteSync(recursive: true);
    }
    iconFontsFile.copySync(outputFile.path);
    Level.info.writeln('生成文件 -> ${outputFile.path}');
  }
  if (_tempDirectory.existsSync()) {
    _tempDirectory.deleteSync(recursive: true);
  }
}
